package com.jred.jforum.actions.common;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.actions.DispatchAction;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class TDDispatchAction extends DispatchAction {
	protected Class[] typesTD = { TDServletWrapper.class };

	protected final static String TD_METHODCACHE_PREFIX = "TD_METHODCACHE_PREFIX";
	protected final static String TD_DEFAULT_METHOD = "main";
	protected final static String TD_NEW_FORWARD_PREFIX = "NEW:";
	
	protected static WebApplicationContext ctx;

	/**
	 * 
	 * 
	 * @param actionServlet
	 * @return
	 */
	public void setServlet(ActionServlet actionServlet) {
		super.setServlet(actionServlet);
		ServletContext servletContext = actionServlet.getServletContext();
		ctx = WebApplicationContextUtils
				.getWebApplicationContext(servletContext);
	}

	/**
	 * 
	 * 
	 * @return WebApplicationContext
	 */
	public static WebApplicationContext getCtx() {
		return ctx;
	}
	
    public Object getServiceFacade(String serviceFacadeName)
    {
        return (Object) ctx.getBean(serviceFacadeName);
    }

	protected Method getMethodTD(String name) throws NoSuchMethodException {

		String cacheKey = TD_METHODCACHE_PREFIX + name;

		synchronized (methods) {
			Method method = (Method) methods.get(cacheKey);

			if (method == null) {
				method = clazz.getMethod(name, typesTD);
				methods.put(cacheKey, method);
			}

			return (method);
		}
	}

	protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		return dispatchMethod(mapping, form, request, response,
				TD_DEFAULT_METHOD);
	}

	protected ActionForward dispatchMethod(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response, String name) throws Exception {

		if (name == null) {
			return this.unspecified(mapping, form, request, response);
		}

		Method method = null;

		// TD: Modified by Wei Zijun
		boolean useTDMethod = false;
		try {
			// 按传统方式取 action方法
			method = getMethod(name);
		} catch (NoSuchMethodException ex) {
			try {
				// 没取到的话 再按新方式取 action方法
				method = getMethodTD(name);
				// 标识一下到底是使用的原始方法 还是新方法
				useTDMethod = true;
			} catch (NoSuchMethodException e) {
				String message = messages.getMessage("dispatch.method", mapping
						.getPath(), name);

				log.error(message, e);

				String userMsg = messages.getMessage("dispatch.method.user",
						mapping.getPath());
				throw new NoSuchMethodException(userMsg);
			}

		}

		ActionForward forward = null;

		try {
			// TD: Modified by Wei Zijun
			Object forwardR = null;

			if (!useTDMethod) {
				// 如果是原始 action 方法
				Object[] args = { mapping, form, request, response };
				forwardR = method.invoke(this, args);

			} else {
				// 如果是新 action 方法
				// TDServletWrapperFactory.getInstance创建一个封装的对象
				Object[] args = { TDServletWrapperFactory.getInstance(mapping,
						form, request, response) };
				forwardR = method.invoke(this, args);
			}

			if (forwardR != null) {
				if (forwardR instanceof ActionForward) {
					forward = (ActionForward) forwardR;
				} else {
					// 如果返回值是字符串:
					// 以 TD_NEW_FORWARD_PREFIX("NEW:")开头,则new ActionForward;
					// 否则 调用 mapping.findForward.
					if ((String.valueOf(forwardR)).toUpperCase().startsWith(
							TD_NEW_FORWARD_PREFIX)) {
						forward = new ActionForward(String.valueOf(forwardR)
								.substring(TD_NEW_FORWARD_PREFIX.length()));
					} else {
						forward = mapping.findForward(String.valueOf(forwardR));
					}
				}
			}

		} catch (ClassCastException e) {
			String message = messages.getMessage("dispatch.return", mapping
					.getPath(), name);

			log.error(message, e);
			throw e;
		} catch (IllegalAccessException e) {
			String message = messages.getMessage("dispatch.error", mapping
					.getPath(), name);

			log.error(message, e);
			throw e;
		} catch (InvocationTargetException e) {

			Throwable t = e.getTargetException();

			if (t instanceof Exception) {
				throw ((Exception) t);
			} else {
				String message = messages.getMessage("dispatch.error", mapping
						.getPath(), name);

				log.error(message, e);
				throw new ServletException(t);
			}
		}

		return (forward);
	}

}
